from django.forms import model_to_dict

from django.db import models


def obj_to_dict(instance, fields=None, exclude=None):
    """
    用于将实例对象转化为其所有属性构成的字典，外键字段会更换为对应的模型类对象，不包含不会包含editable=False字段
    :param instance: 对象实例
    :param fields: 转换的字段
    :param exclude: 排除的字段
    :return:
    """
    raw_dict = model_to_dict(instance, fields=None, exclude=None)
    foreign_key_fields = [field for field in instance._meta.get_fields() if
                          field.is_relation and field.many_to_one]
    for field in foreign_key_fields:
        if raw_dict.get(field.name):
            raw_dict[field.name] = getattr(instance, field.name)
    return raw_dict


def compare_data_dict(dict1, dict2, instance):
    """
    用于比较当前传递参数与数据库中原有参数的差异
    :param dict1: （新字典）当前要修改参数构成的字典，一般为dict(serializer.validated_data)通过序列化器后的参数字典
    :param dict2: （老字典）要修改的模型类对象原有的所有参数构成的字典，一般为obj_to_dict(instance)
    :param instance: 要修改的模型类对象
    :return:
    """
    diff = []
    choices_dict = {}
    for field in instance._meta.fields:
        if field.choices:
            choices_dict[field.name] = dict(field.choices)

    # choices_dict —— {'priority': {'danger': '高', 'warning': '中', 'success': '低'}}
    # 为当前模型类含有choices的字段和对应的选项字典

    # 循环新字典寻找差异
    for k, v in dict1.items():
        # 如果传入值与原值一样，则不记录变更信息
        if dict1[k] == dict2[k]:
            pass
        else:
            # 查看修改字段是否有verbose_name属性，如果没有则使用字段本身的变量名
            k_verbose_name = getattr(instance._meta.get_field(k), 'verbose_name', k)

            # 如果有choices选项，则将更新记录中的值替换为choices字典中的内容
            if choices := choices_dict.get(k):
                msg = f"更改{k_verbose_name}\"{choices.get(dict2[k])}\"为\"{choices.get(dict1[k])}\"\n"

            # 如果字段是列表数据，则将其内元素转换为字符串，主要针对M2M类型，其中是M2M模型的对象，只要定义了__str__方法转换后可自动调取
            elif isinstance(v, list):
                old_list = [str(i) for i in dict2[k]]
                new_list = [str(i) for i in dict1[k]]
                msg = f"更改{k_verbose_name}\"{old_list}\"为\"{new_list}\"\n"

            # 其余一般字段则直接记录变更值
            else:
                msg = f"更改{k_verbose_name}\"{dict2[k]}\"为\"{dict1[k]}\"\n"
            diff.append(msg)
    # 最后返回变更后的记录列表
    return diff


"""
#写在某个模型类中，editable=False字段也会同样显示

from django.db.models.fields import DateTimeField
from django.db.models.fields.related import ManyToManyField

class User(models.Model):
    ...

    def to_dict(self, fields=None, exclude=None):
        data = {}
        for f in self._meta.concrete_fields + self._meta.many_to_many:
            value = f.value_from_object(self)

            if fields and f.name not in fields:
                continue

            if exclude and f.name in exclude:
                continue

            if isinstance(f, ManyToManyField):
                value = [ i.id for i in value ] if self.pk else None

            if isinstance(f, DateTimeField):
                value = value.strftime('%Y-%m-%d %H:%M:%S') if value else None

            data[f.name] = value

        return data
"""
